
#include"process_injector/process_injector.h"

#include "tools/impl/win/WinExpection.h"

#include <boost\lexical_cast.hpp>
#include<Windows.h>
#include<iostream>

#include <string>
#include <vector>

#include<boost/thread.hpp>




class ParseParams
{
public:
	typedef std::pair< std::string, std::vector<std::string> > Library;

	ParseParams( int argc, char** argv ): argc_(argc), argv_(argv), isError_(true)
	{
		for(int i=1; i<argc_;  ++i)
		{
			std::string key = getAsKey(i);
			if(!key.size())
			{
				if(libs_.size())
				{
					loadCmd(i);
					return;
				}else
				{
					libs_.push_back( Library() );
					libs_[0].first = argv_[i];
				}
			}else
			{
				switch(key[0])
				{
				case 'd':{ libs_.push_back( Library() ); libs_[libs_.size()-1].first = argv_[i]; };break;
				case 'p':{ 
							if(!libs_.size())return;  
							libs_[libs_.size()-1].second.push_back(argv_[i]);
						 };break;
				default: return;
				}
			}
		}
	}
	bool isCmd()const
	{
		for(size_t i=0; i < cmd_.size(); i++)
			if( cmd_[i]<'0' || cmd_[i]>'9' )
				return true;
		return false;
	}

	int getId()const
	{
		return 	atoi( cmd_.c_str() );
	}
	std::string getCmd()const{ return cmd_; }
	int getLibCount()const{ return libs_.size(); }
	Library& getLibrary(int index){ return libs_[index]; }
	bool isError()const{ return isError_; }
private:
	typedef std::vector< Library > Librarys;
	std::string getAsKey( int index )
	{
		const char* value = argv_[index];
		if( value[0] == '/' || value[0]=='-' )
			return value+1;
		else
			return "";
	}
	void loadCmd(int index)
	{
		for(int i=index; i < argc_; i++)
		{
			if(i!=index)
				cmd_+=" ";
			cmd_+=argv_[i];
		}
		isError_ = !cmd_.size();
	}

	std::string cmd_;

	Librarys libs_;
	int argc_;
	char** argv_;
	bool isError_;
};



void usage( const std::string& exec_name )
{
	std::cout << "Usage: \n";
	std::cout << exec_name <<" dll_name run_cmd\n"; 
	std::cout << exec_name <<" dll_name process_id"<<std::endl; 
	std::cout << exec_name <<" -d dll1_name [-p dll1_start_param1[ -p dll1_start_param2 [...]]] [-d dll2_name [...]] process_id"<<std::endl; 
	std::cout << exec_name <<" -d dll1_name [-p dll1_start_param1[ -p dll1_start_param2 [...]]] [-d dll2_name [...]] run_cmd"<<std::endl; 
}

int main(int argc,char** argv)
{
	ParseParams params(argc, argv);
	if( params.isError() )
	{
		usage(argv[0]);
		return 1; 
	}

	try
	{

		sd::prin::Process process;

		if( !params.isCmd() )
			process = sd::prin::ProcessInjector::getInstance().attachToProcess( params.getId());
		else
			process = sd::prin::ProcessInjector::getInstance().createProcess( boost::lexical_cast<std::wstring>( params.getCmd().c_str() ) );


		for(int i=0; i < params.getLibCount(); i++)
		{
			std::string lib_args;
			ParseParams::Library& lib = params.getLibrary(i);

			for(size_t j=0; j < lib.second.size(); j++)
			{
				if(j)lib_args+=" ";
				lib_args+=lib.second[j];
			}
			
			process.Inject( boost::lexical_cast<std::wstring>( lib.first.c_str()), boost::lexical_cast<std::wstring>( lib_args.c_str()) );
		}

		//TODO Fix load error
		//std::wcout << "Process " << process.getName().c_str() << ":"<< process.getId() <<std::endl;
		//std::wcout << "Cmd " << process.getCmd().c_str() <<std::endl;


		if(!process.isStarted())
			process.start();
	}catch( const sd::tools::wexception& exp)
	{
		std::wcerr.imbue(std::locale("Russian_russia.OCP"));
		std::wcerr<<L"Catch Error:"<<exp.wwhat();
	}

#ifdef _DEBUG	
	std::cin.get();
#endif
	return 0;
}
